package ar.uba.is2.common.mensaje;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public enum TipoMensaje {
	DATOS {

		private final Pattern DEFAULT_DELIMITER = Pattern.compile(",");
		
		private final Pattern DATOS_SENSADOS_PATTERN = Pattern.compile("\\[.*\\]");
		
		private final Pattern DATO_PATTERN = Pattern.compile("<.*?>");

		
		@Override
		public Mensaje deserializar(String stream) {
			try {
				Mensaje msj = new Mensaje();
				msj.setTipoMensaje(DATOS);
				
				if ( !(stream.startsWith("<") && stream.endsWith(">")) ) {
					return null;
				}

				stream = stream.substring(1, stream.length() - 1);
				Scanner scanner = new Scanner(new StringReader(stream));
				
				scanner.useDelimiter(DEFAULT_DELIMITER);
				
				int numeroMensaje = scanner.nextInt();
				msj.setNumeroMensaje(numeroMensaje);
				
				int cantidadPartes = scanner.nextInt();
				msj.setCantidadPartes(cantidadPartes);
				
				int parte = scanner.nextInt();
				msj.setParte(parte);
				
				long fechaCreacion = scanner.nextLong();
				msj.setFechaCreacion(new Date(fechaCreacion));
				
				String nombreOrigen = scanner.next();
				msj.setOrigen(new Componente(nombreOrigen));

				String nombreDestino = scanner.next();
				msj.setDestino(new Componente(nombreDestino));
				
				String line = scanner.findInLine(DATOS_SENSADOS_PATTERN);
				String datosStream = line.substring(1, line.length() - 1);
				
				scanner = new Scanner(new StringReader(datosStream));
				scanner.useDelimiter(DEFAULT_DELIMITER);
				
				List<DatoSensado> datos = new ArrayList<DatoSensado>();
				String datoStream = null;
				while ((datoStream = scanner.findInLine(DATO_PATTERN)) != null) {
					DatoSensado dato = DatoSensado.deserializar(datoStream);
					datos.add(dato);
				}
				
				msj.setDatos(datos);
				
				return msj;
			} catch (Exception e) {
				return null;
			}
		}

		@Override
		public String serializar(Mensaje msj) {
			return String.format("<%s,%s,%s,%s,%s,%s,%s>", msj
					.getNumeroMensaje(), msj.getCantidadPartes(), msj
					.getParte(), msj.getFechaCreacion().getTime(), msj
					.getOrigen().getNombre(), msj.getDestino().getNombre(), msj
					.getDatos());
		}

	}, ACK {
		
		private Pattern PATTERN_ACK = Pattern.compile("ACK (\\d+)");
		
		@Override
		public Mensaje deserializar(String stream) {
			Mensaje msj = new Mensaje();
			msj.setTipoMensaje(ACK);
			
			Matcher matcher = PATTERN_ACK.matcher(stream);
			
			if(!matcher.matches())
				return null;
			
			int nroMensaje = Integer.valueOf(matcher.group(1));
			msj.setNumeroMensaje(nroMensaje);
			msj.setTipoMensaje(this);
			
			return msj;
		}

		@Override
		public String serializar(Mensaje msj) {
			return String.format("ACK %s", msj.getNumeroMensaje());
		}

	};
	
	public abstract String serializar(Mensaje msj);

	public abstract Mensaje deserializar(String stream);
	
}
